package amtf

import (
	"encoding/json"
	"fmt"
	"server/global"
	"strings"

	"gorm.io/gorm"
)

type Sservice struct {
	A组件 *S组件 `json:"-"`
}

func (a *Sservice) A增(model any, userID uint) (err error) {
	if a.A组件.A自动挡hook.A增s7 != nil {
		if A反射调用(a.A组件.A自动挡hook.A增s7, model) != nil {
			return err
		}
		return
	}
	// 改编号(global.A_DB, model, "", false)
	// err = global.A_DB.Create(model).Error
	// return err

	err = global.A_DB.Transaction(func(tx *gorm.DB) error {
		return A增或改_单个(tx, model, a.A组件, userID)
	})
	return
}

func (a *Sservice) A删(ids any) (err error) {
	组件 := a.A组件
	model, models, _ := A解构组件(组件)
	// db := global.A_DB
	db := global.A_DB.Model(model)
	db = db.Where("id in ?", ids)
	// Preload需要在where之后，不然Preload会被清空👇
	关联查询_可迭代(db, 组件, true, "")

	db = db.Debug()
	err = db.Find(models).Error
	modelsValue := A取反射el(models)
	err = global.A_DB.Transaction(func(tx *gorm.DB) error {
		for i := range modelsValue.Len() {
			model := modelsValue.Index(i).Interface()
			if err = A删_单个_可迭代(tx, model, 组件); err != nil {
				return err
			}
			// tx.Delete(model指针)
		}
		return err
	})
	return err

	// 这种不能关联删除子级👇
	// err = global.A_DB.Delete(models, "id in ?", ids).Error

	// gorm这种只能关联删子级，不能同时删除孙级
	// if modelsValue.Kind() == reflect.Slice {
	// 	for i := 0; i < modelsValue.Len(); i++ {
	// 		model指针 := modelsValue.Index(i).Interface()
	// 		db := global.A_DB
	// 		db = db.Select(clause.Associations)
	// 		// 硬删除👇
	// 		// db = db.Unscoped()
	// 		db = db.Debug()
	// 		db.Delete(model指针)
	// 	}
	// }

}

func (a *Sservice) 流程动作(id uint, userID uint, 动作名称 string) (err error) {
	model, _ := a.A查单个(A转string(id), userID)
	if err = A证接管人(model, a.A组件); err != nil {
		return
	}

	// 流程动态, _ := A查单个_流程动态(model, a.A组件)
	// if 流程动态.A操作人_S用户modelID != userID {
	// 	user := A取user(流程动态.A操作人_S用户modelID)
	// 	return fmt.Errorf(" 本状态👉 <b>%s</b> 由 <b>%s</b> 接管，您 没有操作权限！", 流程动态.A记录状态, user.UserName)
	// }

	状态 := A取状态(model)
	状态候选值 := A解数组(a.A组件.A状态候选值)
	当前序号 := A取序号(状态, 状态候选值)
	var 拟改序号 int
	switch 动作名称 {
	case "退回":
		if 当前序号 == 0 {
			return fmt.Errorf(" 已经是最初状态，不能再退了！")
		}
		拟改序号 = A上一个序号(当前序号, 状态候选值)
	case "下一步":
		拟改序号 = A下一个序号(当前序号, 状态候选值)
	}

	A予字段值(model, "A状态", 状态候选值[拟改序号])
	if err = global.A_DB.Updates(model).Error; err != nil {
		return err
	}
	return
}

func (a *Sservice) A改(model any, userID uint) (err error) {
	if a.A组件.A自动挡hook.A改之前s7 != nil {
		if A反射调用(a.A组件.A自动挡hook.A改之前s7, model) != nil {
			return err
		}
	}
	err = global.A_DB.Transaction(func(tx *gorm.DB) error {
		return A增或改_单个(tx, model, a.A组件, userID)
	})

	// id := A取id(model)
	// 处理主表👇
	// tx := global.A_DB
	// // if err = tx.Model(&model).Where("id =?", id).Updates(model).Error; err != nil {
	// tx = tx.Session(&gorm.Session{FullSaveAssociations: true})
	// tx = tx.Debug()
	// if err = tx.Updates(model).Error; err != nil {
	// 	return err
	// }
	// 记录更新用户(&userID, model)

	return
}

func (a *Sservice) A改多个(models any, userID uint) (err error) {
	models反射值 := A取反射el(models)
	err = global.A_DB.Transaction(func(tx *gorm.DB) error {
		for i := range models反射值.Len() {
			model := models反射值.Index(i).Interface()
			if err2 := A增或改_单个(tx, model, a.A组件, userID); err2 != nil {
				return err2
			}
		}
		return nil
	})
	return err
}

func (a *Sservice) A查单个(ID string, userID uint) (model any, err error) {
	model, _, _ = A解构组件(a.A组件)
	// model = A实例转指针(model)
	// err = global.A_DB.Where("id = ?", ID).First(model).Error

	db := global.A_DB.Debug().Where("id = ?", ID)
	直接放行, 允许用户ids, err := A证数据权限(userID)
	if err != nil {
		return
	} else if !直接放行 {
		db = db.Where("created_by in ?", 允许用户ids)
	}
	// Preload需要在where之后，不然Preload会被清空👇
	关联查询_可迭代(db, a.A组件, false, "")
	err = db.First(model).Error
	return
}

func (a *Sservice) A查单个_公开(ID uint) (model any, err error) {
	model, _, _ = A解构组件(a.A组件)
	db := global.A_DB.Debug().Where("id = ?", ID)
	// Preload需要在where之后，不然Preload会被清空👇
	关联查询_可迭代(db, a.A组件, false, "")
	err = db.First(model).Error
	return
}

// 通过外键找关联组件中的子字段👇
func (a *Sservice) A成外键关联字段集(req S关联表req) (res map[string]map[string]any, err error) {
	res = make(map[string]map[string]any)
	// 字段map := make(map[string]*S字段)
	// for _, 字段 := range 组件.A字段组 {
	// 	字段map[字段.A名称] = 字段
	// }
	外键组 := make([]map[string]any, 0)
	json.Unmarshal([]byte(req.A外键组), &外键组)
	for _, 单个 := range 外键组 {
		外键字段名原值 := 单个["字段名"]
		外键字段名, _ := 外键字段名原值.(string)
		id := 单个["id"]

		单项组 := make(map[string]any, 0)

		关联组件id := ""
		if A含其中之一(外键字段名, "创建者|更新者|删除者", true) {
			关联组件id = "基础.用户"
		} else {
			组件 := a.A组件
			字段id := A成字段id_从组件(组件, 外键字段名)
			字段 := A字段集[字段id]
			// 关联类型为属于，关联组件结构体存储在字段上的情景👇
			if 字段.A关联组件 != nil {
				关联组件id = A成组件id_从自己(字段.A关联组件)
			} else { //其他关联类型👇
				关联组件id = A成组件id(字段.A关联插件名, 字段.A关联组件名)
			}
		}
		关联组件 := A组件集[关联组件id]
		表名 := 关联组件.A表名

		global.A_DB.Table(表名).Where("id = ?", id).Scan(&单项组)
		res[外键字段名] = 单项组
	}
	return
}

func (a *Sservice) A成候选值集() (res map[string][]map[string]any, err error) {
	res = make(map[string][]map[string]any)
	组件 := a.A组件
	if 组件.A树结构 != nil {
		树结构 := make(map[string]string)
		json.Unmarshal([]byte(组件.A树结构), &树结构)
		// res["父级id"] = a.A成候选值(树结构["关联显示字段"])
		res["父级id"] = a.A成候选值(树结构["label"])
		res["父级id"+"树"] = A成树组_非结构体版(res["父级id"], 0)
	}
	for _, 字段 := range 组件.A字段组 {
		if 字段.A类型 == "关联字段" {
			// 关联属性 := A解对象(字段.A关联属性)
			// 关联显示字段 := 关联属性["关联显示字段"]
			// if 关联显示字段 == "" {
			// 	continue
			// } else {
			// 	res[字段.A外键字段名] = 字段.A关联组件.Aservice.A成候选值(关联显示字段)
			// 	if 字段.A关联组件.A树结构 != nil {
			// 		res[字段.A外键字段名+"树"] = A成树组_非结构体版(res[字段.A外键字段名], 0)
			// 	}
			// }
			// 如果已经通过外键处理过👇
			if res[字段.A外键字段名] != nil {
				continue
			} else {
				关联组件 := 字段.A关联组件
				res[字段.A外键字段名] = 关联组件.Aservice.A成候选值("")
				if 关联组件.A树结构 != nil {
					res[字段.A外键字段名+"树"] = A成树组_非结构体版(res[字段.A外键字段名], 0)
				}
			}
		} else if 字段.A是外键 {
			if res[字段.A名称] != nil {
				continue
			} else {
				关联组件 := A取外键关联组件(字段)
				res[字段.A名称] = 关联组件.Aservice.A成候选值("")
				if 关联组件.A树结构 != nil {
					res[字段.A名称+"树"] = A成树组_非结构体版(res[字段.A名称], 0)
				}
			}
		} else if 字段.A候选值源字段 != "" {
			单项组 := A取候选值单项组(字段)
			// 单项组 := make([]map[string]any, 0)
			// // sps := A拆分组件id(字段.A候选值源字段)
			// // 插件名 := sps[0]
			// // 组件名 := sps[1]
			// // 字段名 := sps[2]
			// // 表名 := A成表名(插件名, 组件名)
			// // 传递 插件名.组件名.字段名
			// 源组件, 源字段 := A取字段(字段.A候选值源字段)
			// 组件名 := 源组件.A名称
			// 表名 := 源组件.A表名
			// // 如果是设置的，不能直接取字段，没有直接定义结构体👇
			// if 组件名 == "设置" {
			// 	_, _, 字段名 := A拆分字段id(字段.A候选值源字段)
			// 	var 字段值 string
			// 	global.A_DB.Table(表名).Where("名称 = ?", 字段名).Select("内容").Scan(&字段值)
			// 	var values []string
			// 	json.Unmarshal([]byte(字段值), &values)
			// 	for _, value := range values {
			// 		item := map[string]any{
			// 			"label": value,
			// 			"value": value,
			// 		}
			// 		单项组 = append(单项组, item)
			// 	}
			// } else {
			// 	字段名 := 源字段.A名称
			// 	lable := 字段名
			// 	value := 字段名
			// 	global.A_DB.Table(表名).Where("deleted_at IS NULL").Select(fmt.Sprintf("%s as label, %s as value", lable, value)).Scan(&单项组)
			// 	// global.A_DB.Table("lysd_商品").Where("deleted_at IS NULL").Select("类别 as label,id as value").Scan(&父级id)
			// }

			res[字段.A名称] = 单项组
		} else {
			continue
		}

	}
	return
}

func (a *Sservice) A成候选值(关联显示字段 string) (单项组 []map[string]any) {
	model, _, _ := A解构组件(a.A组件)
	db := global.A_DB.Model(model)
	单项组 = make([]map[string]any, 0)
	成候选值字段名组 := A解数组(a.A组件.A成候选值字段名组)
	if len(成候选值字段名组) == 0 {
		成候选值字段名组 = append(成候选值字段名组, "名称")
		成候选值字段名组 = append(成候选值字段名组, "user_name")
	}
	成候选值字段名组 = append(成候选值字段名组, "父级id", "编号")
	最终字段名组 := []string{}
	for _, v := range 成候选值字段名组 {
		字段名 := A取字段名称go(v)
		if A有字段否(model, 字段名) {
			最终字段名组 = append(最终字段名组, 字段名)
		}
	}
	最终字段名组 = append([]string{"id"}, 最终字段名组...)

	db = db.Select(最终字段名组)
	db.Scan(&单项组)
	// db = db.Select(fmt.Sprintf("%s as label, id as value,父级id", 关联显示字段))

	// err := db.Scan(&单项组)
	// if err != nil {
	// 	db2 := global.A_DB.Model(model)
	// 	db2 = db2.Select(fmt.Sprintf("%s as label, id as value", 关联显示字段))
	// 	db2.Scan(&单项组)
	// }
	// if a.A组件.A树结构 != nil {
	// 	db = db.Select(fmt.Sprintf("%s as label, id as value,父级id", 关联显示字段))
	// 	db = db.Debug()
	// 	db.Scan(&单项组)
	// 	单项组 = A成树组_非结构体版(单项组, 0)
	// }
	return
}

func (a *Sservice) A查(info S列表req, userID uint) (models any, total int64, err error) {
	model, models, _ := A解构组件(a.A组件)
	组件 := a.A组件
	db := global.A_DB.Model(model)
	直接放行, 允许用户ids, err := A证数据权限(userID)

	join := a.A组件.A自动挡hook.Ajoin
	表名 := a.A组件.A表名

	if err != nil {
		return
	} else if !直接放行 {
		// fmt.Printf("允许用户ids 👉 %+v\n", 允许用户ids)
		// db = db.Where("created_by in ?", 允许用户ids)
		if join == nil {
			db = db.Where("created_by in ?", 允许用户ids)
		} else {
			// 有join的情况下，因为会加上SELECT ，所以WHERE 需要加上 表名 限定
			// SELECT 项目管理_项目信息.*,d1.名称 as 办事处,d2.名称 as 大区 FROM `项目管理_项目信息` left join 基础_人员 on 基础_人员.系统用户_用户id = 项目管理_项目信息.created_by left join 基础_部门 d1 on d1.id = 基础_人员.部门_部门id left join 基础_部门 d2 on d2.id = d1.父级id WHERE 项目管理_项目信息.created_by in (5,1)
			var idStrings []string
			for _, id := range 允许用户ids {
				idStrings = append(idStrings, fmt.Sprintf("%d", id))
			}
			idList := "(" + strings.Join(idStrings, ",") + ")"
			sql := fmt.Sprintf("%s.created_by in %s", 表名, idList)
			db = db.Where(sql)
		}
	}

	// 处理需要join的字段👇
	// 要放在其他Where的后面👇，后面的筛选可能也会有问题？
	if join != nil {
		A反射调用(join, db)
	}
	// db.Select("*", "项目管理_人员.姓名 as 员工姓名", "d1.名称 as 办事处", "d2.名称 as 大区").
	// 	Joins("left join 项目管理_人员 on 项目管理_人员.用户id = 项目管理_项目信息.updated_by").
	// 	Joins("left join 项目管理_部门 d1 on d1.id = 项目管理_人员.部门id").
	// 	Joins("left join 项目管理_部门 d2 on d2.id = d1.父级id")

	limit := info.PageSize
	offset := info.PageSize * (info.Page - 1)

	// 用户主动要求
	// if info.A仅自己 {
	// 	db = db.Where("created_by = ?", info.A用户id)
	// }
	if len(info.IDS) > 0 {
		db = db.Where("id in ?", info.IDS)
	}

	// 处理关联查询👇
	关联查询_可迭代(db, a.A组件, false, "")
	// 关联查询_可迭代(db, a.A组件, true, "")
	// db.Preload(clause.Associations)

	// if len(info.A关联查询字段名s) > 0 {
	// 	for _, 字段名 := range info.A关联查询字段名s {
	// 		db = db.Joins("A" + 字段名)
	// 	}
	// }
	// db = db.Joins("A"+"人员", db.Where("用户id = ?", 1).Select("A人员.姓名, A人员.部门id"))

	// 处理需要查询关联字段中的子字段的情况，比如前端传递👇
	// 多字段搜索字段名s: ["姓名", "部门.名称"],
	if info.A多字段搜索关键词 != "" {
		字段值 := info.A多字段搜索关键词
		var conditions []string
		var args []any
		// if len(info.A多字段搜索字段名s) > 0 {
		// 	需join的表对应字段名map := make(map[string]any)
		// 	for _, 字段名 := range info.A多字段搜索字段名s {
		// 		sps := A拆分组件id(字段名)
		// 		// 一对一和多的情况：前端给的字段名是 部门.名称 自己model中的关联字段的名称👇
		// 		if len(sps) > 1 {
		// 			// 字段名 = "A" + 字段名
		// 			字段名 = A取字段名称go(字段名)

		// 			// 需join的表对应字段名map["A"+sps[0]] = nil
		// 			需join的表对应字段名map[A取字段名称go(sps[0])] = nil
		// 		} else {
		// 			if join != nil {
		// 				字段名 = A予join源字段名(组件, 字段名)
		// 			}
		// 		}
		// 		conditions = append(conditions, 字段名+" LIKE ?")
		// 		args = append(args, "%"+字段值+"%") // 使用通配符进行模糊搜索
		// 	}

		// 	// 先把关联表通过结构体中的字段名join进来，
		// 	for k := range 需join的表对应字段名map {
		// 		db = db.Joins(k)
		// 	}
		// }

		for _, 字段 := range 组件.A字段组 {
			关联类型, _ := A解关联属性(字段)
			if 关联类型 != "" {
				continue
			}
			// if 字段.A类型_go != "string" {
			// 	continue
			// }
			字段名 := 字段.A名称
			if join != nil {
				字段名 = A予join源字段名(组件, 字段名)
			}
			conditions = append(conditions, 字段名+" LIKE ?")
			args = append(args, "%"+字段值+"%") // 使用通配符进行模糊搜索
		}
		sql := strings.Join(conditions, " OR ")
		fmt.Printf("sql 👉 %+v\n", sql)
		// 再查询字段
		db = db.Where(sql, args...)
	}

	if len(info.A筛选组) > 0 {
		筛选组 := make([]map[string]any, 0)
		json.Unmarshal([]byte(info.A筛选组), &筛选组)
		for _, 筛选 := range 筛选组 {
			if len(筛选) > 0 {
				// 字段名 :=
				字段名, _ := 筛选["字段名"].(string)
				if join != nil {
					字段名 = A予join源字段名(组件, 字段名)
					// 字段 := A字段集[A成字段id_从组件(组件, 字段名)]
					// if 字段.Ajoin属性 != nil {
					// 	join属性 := A解对象(字段.Ajoin属性)
					// 	join字段id := join属性["join字段id"]
					// 	_, _, join字段名 := A拆分字段id(join字段id)
					// 	字段名 = join字段名
					// }
				}

				符号 := 筛选["比较运算符"]
				字段值 := 筛选["字段值"]
				sql := ""
				switch 符号 {
				case "=":
					断言值, _ := 字段值.(string)
					// // SELECT * FROM `项目管理_人员` WHERE 姓名 like '%八%'
					字段值 = "'" + 断言值 + "'"
				case "like":
					断言值, _ := 字段值.(string)
					// SELECT * FROM `项目管理_人员` WHERE 姓名 like '%八%'
					字段值 = "'%" + 断言值 + "%'"
				case "in":
					断言值, ok := 字段值.([]any)
					if ok {
						placeholders := make([]string, len(断言值))
						for i, v := range 断言值 {
							placeholders[i] = fmt.Sprintf("%v", v)
						}
						字段值 = fmt.Sprintf("(%s)", strings.Join(placeholders, ","))
					} else {
						fmt.Println("字段值 is not a slice")
					}
				case "±?%":
					// 百分数 := 筛选["百分数"]
					百分数, _ := 筛选["百分数"].(float64)
					基准数, _ := 筛选["基准数"].(float64)
					最小值 := 基准数 * (1 - 百分数/100)
					最大值 := 基准数 * (1 + 百分数/100)
					sql = fmt.Sprintf("%s BETWEEN %f AND %f", 字段名, 最小值, 最大值)
				}
				if sql == "" {
					sql = fmt.Sprintf("%s %s %s", 字段名, 符号, 字段值)
				}
				// 当字段的数据类型为字符串类型（如 VARCHAR、CHAR、TEXT 等）时，需要在值的两侧添加单引号。这是因为在 SQL 中，字符串值必须用单引号括起来，以区分它们和其他类型的值（如数字、布尔值等）
				// sql := fmt.Sprintf("%s %s '%s'", 字段名, 符号, 字段值)
				db = db.Where(sql)
			}
		}
	}

	err = db.Count(&total).Error
	if err != nil {
		return nil, 0, err
	}

	// 排序👇
	var OrderStr string
	OrderStr = info.Sort
	OrderStr = A转小写(OrderStr)
	// OrderStr = "updated_at"
	if info.Order == "descending" {
		OrderStr = OrderStr + " desc"
	}
	db = db.Order(OrderStr)

	if limit != 0 {
		db = db.Limit(limit).Offset(offset)
	}

	db = db.Debug()
	err = db.Find(models).Error
	// A打印models(models)
	if info.A树结构 {
		models = A成树组(models, 0)
	}
	// A打印models(models)
	if err != nil {
		return nil, 0, err
	}
	return
}

func (a *Sservice) 查多个(info S列表req) (models any) {
	model, models, _ := A解构组件(a.A组件)
	db := global.A_DB.Model(model)
	db = db.Debug()
	_ = db.Find(models).Error
	return
}

func (a *Sservice) A查_加载所有关联项() (models any, err error) {
	model, models, _ := A解构组件(a.A组件)
	db := global.A_DB.Model(model)
	关联查询_可迭代(db, a.A组件, true, "")
	// 关联查询_可迭代(db, a.A组件, false,"")
	db = db.Debug()
	err = db.Find(models).Error
	if err != nil {
		return nil, err
	}
	return
}

func (a *Sservice) A查设置() (models any, total int64, err error) {
	model, models, _ := A解构组件(a.A组件)
	db := global.A_DB.Model(model)

	err = db.Count(&total).Error
	if err != nil {
		return nil, 0, err
	}

	err = db.Find(models).Error
	if err != nil {
		return nil, 0, err
	}
	return
}

func (a *Sservice) A查作废保留(info S列表req) (models any, total int64, err error) {
	model, models, _ := A解构组件(a.A组件)

	limit := info.PageSize
	offset := info.PageSize * (info.Page - 1)
	// model := 组件.Amodel
	// models = 组件.Amodels

	db := global.A_DB.Model(model)

	// 处理关联字段
	// for _, 字段 := range 组件.A字段组 {
	// 	switch 字段.A类型 {
	// 	case "关联字段":
	// 		关联属性 := 字段.A关联属性
	// 		关联类型 := 关联属性["关联类型"]
	// 		//形如👉 A商品  shangpin.S商品model  `json:"商品" gorm:"-"`
	// 		// sps := A拆分组件id(字段.A类型_go)
	// 		if 关联类型 == "一对一属于" {
	// 			// err = global.A_DB.Preload("Good").Preload("SKU").Find(&list, "user_id = ?", userID).Error
	// 			db = db.Preload(字段.A名称go)
	// 		}
	// 	}
	// }
	关联查询_可迭代(db, a.A组件, false, "")

	// db = db.Preload("A商品")
	// 按条件筛选查找👇
	// if info.A修改开始点 != nil && info.A修改结束点 != nil {
	// 	db = db.Where("updated_at BETWEEN ? AND ?", info.A修改开始点, info.A修改结束点)
	// } else if info.A修改开始点 != nil && info.A修改结束点 == nil {
	// 	db = db.Where("updated_at >=?", info.A修改开始点)
	// } else if info.A修改开始点 == nil && info.A修改结束点 != nil {
	// 	db = db.Where("updated_at <=?", info.A修改结束点)
	// }

	if info.A仅自己 {
		db = db.Where("用户id = ?", info.A用户id)
	}

	if len(info.IDS) > 0 {
		db = db.Where("id in ?", info.IDS)
	}

	if info.A多字段搜索关键词 != "" {
		字段值 := info.A多字段搜索关键词
		if len(info.A多字段搜索字段名s) > 0 {
			var conditions []string
			var args []any
			for _, 字段名 := range info.A多字段搜索字段名s {
				conditions = append(conditions, 字段名+" LIKE ?")
				args = append(args, "%"+字段值+"%") // 使用通配符进行模糊搜索
			}
			sql := strings.Join(conditions, " OR ")
			fmt.Printf("sql 👉 %+v\n", sql)
			db = db.Where(sql, args...)
		}
	} else {
		// if len(info.A筛选) > 0 {
		// 	for _, 筛选 := range info.A筛选 {
		// 		符号 := "="
		// 		split := strings.Split(筛选, 符号)
		// 		if len(split) > 1 {
		// 			字段名 := split[0]
		// 			字段值 := split[1]
		// 			sql := fmt.Sprintf("%s %s '%s'", 字段名, 符号, 字段值)
		// 			db = db.Where(sql)
		// 		}
		// 	}
		// }
	}

	err = db.Count(&total).Error
	if err != nil {
		return nil, 0, err
	}

	// 排序👇
	var OrderStr string
	OrderStr = info.Sort
	OrderStr = A转小写(OrderStr)
	// OrderStr = "updated_at"
	if info.Order == "descending" {
		OrderStr = OrderStr + " desc"
	}
	db = db.Order(OrderStr)

	if limit != 0 {
		db = db.Limit(limit).Offset(offset)
	}

	db = db.Debug()
	err = db.Find(models).Error

	if info.A树结构 {
		models = A成树组(models, 0)
	}

	if err != nil {
		return nil, 0, err
	}
	return
}
